
#include "mp3Parse.h"

// 文件头
typedef struct
{
    uint8_t header[3]; // 文件头
    uint8_t ver;       // 文件版本
    uint8_t revision;  // 子版本
    uint8_t flag;      // 标记
    uint8_t size[4];   // 大小
} mp3FileHeader_t;

// 标签头
typedef struct
{
    uint8_t header[4]; // 头
    uint8_t size[4];   // 标签大侠
    uint8_t flag[2];   // 标签属性
} mp3LableHeader_t;

// 标签头标志位的解析
typedef struct
{
    bool tagProtection;  // 标签保护
    bool fileProtection; // 文件保护
    bool readOnly;       // 只读
    bool compression;    // 压缩
    bool encrypt;        // 加密
    bool group;          // 属于某一组
} mp3LableHeaderFlag_t;

uint32_t parseMp3FileHeader(mp3FileHeader_t fileHeader)
{
    uint32_t mp3size = 0;
    mp3size += (fileHeader.size[0] & 0x7f) * 0x200000;
    mp3size += (fileHeader.size[1] & 0x7f) * 0x400;
    mp3size += (fileHeader.size[2] & 0x7f) * 0x80;
    mp3size += fileHeader.size[3] & 0x7f;
    printf("fileHeader [%s] ver [%d] revision [%d] flag [%#x] mp3size [%d]\n",
           fileHeader.header,
           fileHeader.ver,
           fileHeader.revision,
           fileHeader.flag,
           //    fileHeader.size,
           mp3size);

    return mp3size;
}

uint32_t parseMp3LabelHeader(mp3LableHeader_t labheader)
{
    uint32_t mp3size = 0;

    // 解析标签头
    mp3size += labheader.size[0] * 0x100000000;
    mp3size += labheader.size[1] * 0x10000;
    mp3size += labheader.size[2] * 0x100;
    mp3size += labheader.size[3];

    mp3LableHeaderFlag_t mp3LableHeaderFlag = {0};
    mp3LableHeaderFlag.tagProtection = labheader.flag[0] & 0x80;
    mp3LableHeaderFlag.fileProtection = labheader.flag[0] & 0x40;
    mp3LableHeaderFlag.readOnly = labheader.flag[0] & 0x20;
    mp3LableHeaderFlag.compression = labheader.flag[1] & 0x08;
    mp3LableHeaderFlag.encrypt = labheader.flag[1] & 0x04;
    mp3LableHeaderFlag.group = labheader.flag[1] & 0x02;
    printf("labheader [%s] labelSize [%d] \nlabheaderflag  tagProtection %d fileProtection %d readOnly %d compression %d encrypt %d group %d\n",
           labheader.header,
           mp3size,
           mp3LableHeaderFlag.tagProtection,
           mp3LableHeaderFlag.fileProtection,
           mp3LableHeaderFlag.readOnly,
           mp3LableHeaderFlag.compression,
           mp3LableHeaderFlag.encrypt,
           mp3LableHeaderFlag.group);

    return mp3size;
}

typedef struct
{
    uint8_t *type;
    uint32_t (*parseDataCb)(uint8_t *data, uint32_t datalen);
} mp3LabelParse_t;

uint32_t APIC(uint8_t *data, uint32_t datalen)
{
    printf("this a picture not parse !!!!\n");

    return 0;
}
uint32_t COMM(uint8_t *data, uint32_t datalen)
{
    printf("%s\n", data + 1);
    printf("%s\n", data + 5);
    return 0;
}
uint32_t TSSE(uint8_t *data, uint32_t datalen)
{
    return 0;
}
uint32_t TALB(uint8_t *data, uint32_t datalen)
{
    return 0;
}
uint32_t TIT2(uint8_t *data, uint32_t datalen)
{

    return 0;
}
uint32_t TPE1(uint8_t *data, uint32_t datalen)
{
    return 0;
}
uint32_t TPOS(uint8_t *data, uint32_t datalen)
{
    return 0;
}
uint32_t TRCK(uint8_t *data, uint32_t datalen)
{
    return 0;
}

mp3LabelParse_t mp3TabParseFunc[] = {
    {"AENC", NULL}, // Audioencryption
    {"APIC", APIC}, // Attached picture
    {"COMM", COMM}, // Comments
    {"COMR", NULL}, // Commercial
    {"ENCR", NULL}, // Encryptionmethod registration
    {"EQUA", NULL}, // Equalization
    {"ETCO", NULL}, // Event timingcodes
    {"GEOB", NULL}, // Generalencapsulated object
    {"GRID", NULL}, // Groupidentification registration
    {"IPLS", NULL}, // Involvedpeople list
    {"LINK", NULL}, // Linkedinformation
    {"MCDI", NULL}, // Music CDidentifier
    {"MLLT", NULL}, // MPEGlocationlookup table
    {"OWNE", NULL}, // Ownership
    {"PRIV", NULL}, // Private
    {"PCNT", NULL}, // Playcounter
    {"POPM", NULL}, // Popularimeter
    {"POSS", NULL}, // Positionsynchronisation
    {"RBUF", NULL}, // Recommendedbuffer size
    {"RVAD", NULL}, // Relativevolume adjustment
    {"RVRB", NULL}, // Reverb
    {"SYLT", NULL}, // Synchronizedlyric/text
    {"SYTC", NULL}, // Synchronizedtempo codes
    {"TALB", TALB}, // Album/Movie/Showtitle
    {"TBPM", NULL}, // BPM(beats perminute)
    {"TCOM", NULL}, // Composer
    {"TCON", NULL}, // Content type
    {"TCOP", NULL}, // Copyrightmessage
    {"TDAT", NULL}, // Date
    {"TDLY", NULL}, // Playlistdelay
    {"TENC", NULL}, // Encoded by
    {"TEXT", NULL}, // Lyricist/Textwriter
    {"TFLT", NULL}, // Filetype
    {"TIME", NULL}, // Time
    {"TIT1", NULL}, // Content groupdeion
    {"TIT2", TIT2}, // Title/songname/contentdeion
    {"TIT3", NULL}, // Subtitle/Deionrefinement
    {"TKEY", NULL}, // Initial key
    {"TLAN", NULL}, // Language(s)
    {"TLEN", NULL}, // Length
    {"TMED", NULL}, // Media type
    {"TOAL", NULL}, // Originalalbum/movie/show title
    {"TOFN", NULL}, // Originalfilename
    {"TOLY", NULL}, // Originallyricist(s)/text writer(s)
    {"TOPE", NULL}, // Originalartist(s)/performer(s)
    {"TORY", NULL}, // Originalrelease year
    {"TOWN", NULL}, // Fileowner/licensee
    {"TPE1", TPE1}, // Leadperformer(s)/Soloist(s)
    {"TPE2", NULL}, // Band/orchestra/accompaniment
    {"TPE3", NULL}, // Conductor/performerrefinement
    {"TPE4", NULL}, // Interpreted,remixed, or otherwise modified by
    {"TPOS", TPOS}, // Partof a set
    {"TPUB", NULL}, // Publisher
    {"TRCK", TRCK}, // Tracknumber/Position in set
    {"TRDA", NULL}, // Recordingdates
    {"TRSN", NULL}, // Internetradio station name
    {"TRSO", NULL}, // Internetradio station owner
    {"TSIZ", NULL}, // Size
    {"TSRC", NULL}, // ISRC(internationalstandard recording code)
    {"TSSE", TSSE}, // Software/Hardwareand settings used for encoding
    {"TYER", NULL}, // Year
    {"TXXX", NULL}, // Userdefinedtext information
    {"UFID", NULL}, // Unique fileidentifier
    {"USER", NULL}, // Terms of use
    {"USLT", NULL}, // Unsychronizedlyric/text tranion
    {"WCOM", NULL}, // Commercialinformation
    {"WCOP", NULL}, // Copyright/Legalinformation
    {"WOAF", NULL}, // Officialaudio file webpage
    {"WOAR", NULL}, // Officialartist/performer webpage
    {"WOAS", NULL}, // Officialaudio source webpage
    {"WORS", NULL}, // Officialinternet radio station homepage
    {"WPAY", NULL}, // Payment
    {"WPUB", NULL}, // Publishersofficial webpage
    {"WXXX", NULL}, // UserdefinedURL link
};

// typedef struct
// {
//     uint32_t syn : 11;                       // 同步信息，所有位均为1
//     uint32_t ver : 2;                        // 版本，MPEG1
//     uint32_t layer : 2;                      // 层，Layer3
//     uint32_t existCRC : 1;                   // 无CRC校验
//     uint32_t bitRate : 4;                    // 位率，单位是kbps，320
//     uint32_t samplingRate : 2;               // 采样频率，44.1K
//     uint32_t lengthAdjustment : 1;           // 用来调整文件头长度，无需调整
//     uint32_t reserve : 1;                    // 保留字，未使用
//     uint32_t soundChannel : 2;               // 表示声道模式，立体声Stereo
//     uint32_t stereo : 2;                     // 声道模式为Joint Stereo时才使用
//     uint32_t validityDetection : 1;          // 文件是否合法，不合法
//     uint32_t originalVersion : 1;            // 是否原版，非原版
//     uint32_t noiseReductionCompensation : 2; // 用于声音经降噪压缩后再补偿的分类，未定义
// } mp3DataHeader_t;

// 数据帧头
// 参考文档  https://blog.csdn.net/u010650845/article/details/53520426
typedef struct
{
    uint16_t syn;                       // 同步信息，所有位均为1
    uint8_t ver;                        // 版本，MPEG1
    uint8_t layer;                      // 层，Layer3
    uint8_t existCRC;                   // 无CRC校验
    uint16_t bitRate;                   // 位率，单位是kbps，320
    uint8_t samplingRate;               // 采样频率，44.1K
    uint8_t lengthAdjustment;           // 用来调整文件头长度，无需调整
    uint8_t reserve;                    // 保留字，未使用
    uint8_t soundChannel;               // 表示声道模式，立体声Stereo
    uint8_t stereo;                     // 声道模式为Joint Stereo时才使用
    uint8_t validityDetection;          // 文件是否合法，不合法
    uint8_t originalVersion;            // 是否原版，非原版
    uint8_t noiseReductionCompensation; // 用于声音经降噪压缩后再补偿的分类，未定义
} mp3DataHeader_t;
// ver -->    3         2          1         0
//           mpeg1    mpeg2       xx       mpeg2.5
//  (0)xx    xx       xx          xx       xx
//  (3)L1    384      384         xx       384
//  (2)L2    1152     1152        xx       1152
//  (1)L3    1152     1152        xx       576
//  ⬆
//  layer

// 版本号与层对应的每帧采样数
uint32_t table1[][4] = {
    {0, 576, 1152, 384},
    {0, 0, 0, 0},
    {0, 1152, 1152, 384},
    {0, 1152, 1152, 384},
};

// ver -->    3         2          1         0
//           mpeg1    mpeg2       xx       mpeg2.5
//  (0)xx    44.1     22.05       xx       11.025
//  (3)L1    XX       XX          xx       XX
//  (2)L2    32       16          xx       8
//  (1)L3    48       24          xx       12
//  ⬆
//  samplingRate
// 版本号对应的采样频率
double table2[][4] = {
    {11.025, 12, 8, 0},
    {0, 0, 0, 0},
    {22.05, 24, 16, 0},
    {44.1, 48, 32, 0},
};

#define FREERATE 0
#define BADRATE (-1)
int32_t tableV1L1[] = {FREERATE, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, BADRATE};
int32_t tableV1L2[] = {FREERATE, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, BADRATE};
int32_t tableV1L3[] = {FREERATE, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, BADRATE};

// 除以二就是另一组数据
int32_t tableV2L1[] = {FREERATE, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, BADRATE};
int32_t tableV2L1_1[] = {FREERATE, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, BADRATE};
int32_t tableV2L2[] = {FREERATE, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, BADRATE};
int32_t tableV2L2_1[] = {FREERATE, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, BADRATE};
int32_t tableV2L3[] = {FREERATE, 8, 16, 24, 32, 64, 80, 56, 64, 128, 160, 112, 128, 256, 320, BADRATE};
int32_t tableV2L3_1[] = {FREERATE, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, BADRATE};

enum mp3ver_e
{
    MPEG_25 = 0,
    MPEG_UN,
    MPEG_2,
    MPEG_1,
};
enum mp3layer_e
{
    LAYER_UN = 0,
    LAYER_3,
    LAYER_2,
    LAYER_1,
};

uint32_t bitRateParse(mp3DataHeader_t mp3DataHeader)
{
    uint32_t bitRate = 0;
    switch (mp3DataHeader.ver)
    {
    case MPEG_25:
    case MPEG_2:
        switch (mp3DataHeader.layer)
        {
        case LAYER_3:
            bitRate = tableV2L3[mp3DataHeader.bitRate];
            break;
        case LAYER_2:
            bitRate = tableV2L2[mp3DataHeader.bitRate];
            break;
        case LAYER_1:
            bitRate = tableV2L1[mp3DataHeader.bitRate];
            break;
        default:
            printf("ERROR --> unknown layer 1\n");
            break;
        }
        break;
    case MPEG_1:
        switch (mp3DataHeader.layer)
        {
        case LAYER_3:
            bitRate = tableV1L3[mp3DataHeader.bitRate];
            break;
        case LAYER_2:
            bitRate = tableV1L2[mp3DataHeader.bitRate];
            break;
        case LAYER_1:
            bitRate = tableV1L1[mp3DataHeader.bitRate];
            break;
        default:
            printf("ERROR --> unknown layer 2\n");

            break;
        }
        break;
    default:
        printf("ERROR --> unknown ver 3\n");
        break;
    }

    return bitRate;
}

uint32_t mp3DataHeaderParse(mp3DataHeader_t *mp3DataHeader, uint8_t buf[])
{

    for (int i = 0; i < 4; i++)
    {
        printf("%#x ", buf[i]);
    }
    printf("\n");

    mp3DataHeader->syn |= buf[0];
    mp3DataHeader->syn <<= 3;
    mp3DataHeader->syn |= (buf[1] & 0xE0) >> 5;
    mp3DataHeader->ver |= (buf[1] & 0x18) >> 3;
    mp3DataHeader->layer |= (buf[1] & 0x06) >> 1;
    mp3DataHeader->existCRC |= (buf[1] & 0x01);
    mp3DataHeader->bitRate |= (buf[2] & 0xF0) >> 4;
    mp3DataHeader->samplingRate |= (buf[2] & 0x0C) >> 2;
    mp3DataHeader->lengthAdjustment |= (buf[2] & 0x02) >> 1;
    mp3DataHeader->reserve |= buf[2] & 0x01;
    mp3DataHeader->soundChannel |= (buf[3] & 0xC0) >> 6;
    mp3DataHeader->stereo |= (buf[3] & 0x30) >> 4;
    mp3DataHeader->validityDetection |= (buf[3] & 0x10) >> 3;
    mp3DataHeader->originalVersion |= (buf[3] & 0x04) >> 2;
    mp3DataHeader->noiseReductionCompensation |= buf[3] & 0x03;

    printf("dataHeader syn [%#x] ver [%d] layer [%d] existCRC [%d] bitRate [%#x] samplingRate [%d] lengthAdjustment [%d] reserve [%d] soundChannel [%d] stereo [%d] validityDetection [%d] originalVersion [%d] noiseReductionCompensation [%d]\n",
           mp3DataHeader->syn,
           mp3DataHeader->ver,
           mp3DataHeader->layer,
           mp3DataHeader->existCRC,
           mp3DataHeader->bitRate,
           mp3DataHeader->samplingRate,
           mp3DataHeader->lengthAdjustment,
           mp3DataHeader->reserve,
           mp3DataHeader->soundChannel,
           mp3DataHeader->stereo,
           mp3DataHeader->validityDetection,
           mp3DataHeader->originalVersion,
           mp3DataHeader->noiseReductionCompensation);

    uint32_t frameLen = 0, // 单帧长度
        frameTime = 0,     // 帧持续时间

        //
        unitSamplenumber = 0,   // 每帧采样数
        bitRate = 0,            // 比特率
        fill = 0;               // 填充
    double sampleFrequency = 0; // 采样频率

    // 取得每帧采样数
    unitSamplenumber = table1[mp3DataHeader->ver][mp3DataHeader->layer];
    sampleFrequency = table2[mp3DataHeader->ver][mp3DataHeader->samplingRate];
    bitRate = bitRateParse(*mp3DataHeader);

    switch (mp3DataHeader->layer)
    {
    case LAYER_3:
    case LAYER_2:
        fill = mp3DataHeader->lengthAdjustment;
        break;
    case LAYER_1:
        fill = mp3DataHeader->lengthAdjustment * 4;
        break;
    default:
        printf("ERROR --> unknown layer 4\n");
        break;
    }

    if (bitRate == FREERATE)
    {
        printf("Variable bit rate !!!\n");
    }
    else if (bitRate == BADRATE)
    {
        printf("Unavailable bit rate !!!\n");
    }

    printf("unitSamplenumber %d sampleFrequency %f bitRate %d fill %d\n",
           unitSamplenumber,
           sampleFrequency,
           bitRate,
           fill);
    frameLen = (unitSamplenumber / 8 * bitRate) / sampleFrequency + fill;
    frameTime = unitSamplenumber / sampleFrequency;

    printf("frame length %d  frame time %d ms\n", frameLen, frameTime);

    return frameLen;
}

typedef struct
{
    unsigned int main_data_begin;
    unsigned int private_bits;
    unsigned char scfsi[2];

    struct granule
    {
        struct channel
        {
            /* from side info */
            unsigned short part2_3_length;
            unsigned short big_values;
            unsigned short global_gain;
            unsigned short scalefac_compress;

            unsigned char flags;
            unsigned char block_type;
            unsigned char table_select[3];
            unsigned char subblock_gain[3];
            unsigned char region0_count;
            unsigned char region1_count;

            /* from main_data */
            unsigned char scalefac[39]; /* scalefac_l and/or scalefac_s */
        } ch[2];
    } gr[2];
} mp3Sideinfo_t;

uint32_t mp3ChannelInfoParse(mp3Sideinfo_t channelInfo)
{
    printf("channelInfo main_data_begin %#x private_bits %d \n",
           channelInfo.main_data_begin,
           channelInfo.private_bits);

    for (int i = 0; i < 2; i++)
    {
        for (int i1 = 0; i1 < 2; i1++)
        {

            printf("gr[%d] ch[%d] part2_3_length %d  big_values %d  global_gain %d flags %d  block_type %d region0_count %d region1_count %d \n",
                   i,
                   i1,
                   channelInfo.gr[i].ch[i1].part2_3_length,
                   channelInfo.gr[i].ch[i1].big_values,
                   channelInfo.gr[i].ch[i1].global_gain,
                   channelInfo.gr[i].ch[i1].flags,
                   channelInfo.gr[i].ch[i1].block_type,
                   channelInfo.gr[i].ch[i1].region0_count,
                   channelInfo.gr[i].ch[i1].region1_count

            );
        }
    }
}

typedef struct
{
    uint8_t header[4];
    uint8_t fileFlag[8];
    uint8_t MPEG2_mono[4];
    uint8_t reserve[4];
    union
    {
        uint8_t MPEG2_notmono[4];
        uint8_t MPEG1_mono[4];
    } MPEG1_mono;
    uint8_t reserve2[11];
    uint8_t MPEG1_notmono[4];
    uint8_t reserve3[1];

    //
    uint8_t flag[4];
    uint32_t frameNumber;
    uint32_t fileLength;

    //
    uint8_t menuTable[100];
    uint8_t vbrScale[4];

} mp3VBRHeader_t;

// 参考  https://blog.csdn.net/u010650845/article/details/53520426
typedef struct
{
    uint8_t tag[3];
    uint8_t mp3Name[30];
    uint8_t mp3Author[30];
    uint8_t mp3Album[30];
    uint8_t mp3Year[4];
    uint8_t mp3Note[30];
    uint8_t mp3style[1];

} mp3ID3V1Header_t;

int8_t mp3Parse(uint8_t *fileAddr)
{
    FILE *file = NULL;
    file = fopen(fileAddr, "rb");
    if (file == NULL)
    {
        printf("open file fail\n");
        return -1;
    }

    fseek(file, 0, SEEK_SET);

    // 文件帧
    mp3FileHeader_t fileHeader = {0};
    fread(&fileHeader, 1, sizeof(mp3FileHeader_t), file);
    parseMp3FileHeader(fileHeader);

    // 准备各帧解析函数
    int labelTypeCount = sizeof(mp3TabParseFunc) / sizeof(mp3TabParseFunc[0]);

    //
    bool isLabel = false;
    do
    {
        isLabel = false;

        // 标签帧
        mp3LableHeader_t labheader = {0};
        fread(&labheader, 1, sizeof(mp3LableHeader_t), file);
        uint32_t labelLen = parseMp3LabelHeader(labheader);

        // 标签帧
        for (int i = 0; i < labelTypeCount; i++)
        {
            if (strcmp(labheader.header, mp3TabParseFunc[i].type) == 0)
            {
                printf(" -- > %s\n", mp3TabParseFunc[i].type);
                isLabel = true;

                // 帧内容
                uint8_t *paramData = (uint8_t *)malloc(labelLen);
                if (paramData == NULL)
                {
                    printf("malloc fail\n");
                    break;
                }
                memset(paramData, 0, labelLen);
                fread(paramData, 1, labelLen, file);
                // for (int x = 0; x < labelLen; x++)
                // {
                //     printf("%#x ", paramData[x]);
                // }
                // printf("\n");
                // printf("len %d [%s]\n", labelLen, paramData);

                // 内容解析
                if (mp3TabParseFunc[i].parseDataCb != NULL)
                {
                    mp3TabParseFunc[i].parseDataCb(paramData, labelLen);
                }

                // 释放资源
                if (paramData != NULL)
                {
                    free(paramData);
                    paramData = NULL;
                }
                break;
            }
        }

        if (isLabel == false)
        {
            printf("file index %#x \n", ftell(file));
            uint8_t *p = (uint8_t *)&labheader;
            for (int i = 0; i < 10; i++)
            {
                printf("%02x ", p[i]);
            }
            printf("\n");
        }

    } while (isLabel);

    // 开始处理 数据帧之前的空白间隔
    do
    {
        uint8_t c;
        fread(&c, 1, 1, file);
        if (c != 0)
        {
            break;
        }
    } while (1);

    printf("back data start index %#x\n", ftell(file));
    fseek(file, -1, SEEK_CUR);

    // 开始处理 数据帧头信息以及可能存在的CRC 通道信息
    bool isdataParam = true;
    do
    {
        printf("\n\n");

        uint8_t buf[4] = {0};
        fread(buf, 1, 4, file);
        mp3DataHeader_t mp3DataHeader = {0};
        uint32_t frameLength = mp3DataHeaderParse(&mp3DataHeader, buf);
        if (frameLength <= 0)
        {
            isdataParam = false;
            printf("frameLength %d is not enough!!\n", frameLength);

            fseek(file, -4, SEEK_CUR);

            mp3ID3V1Header_t mp3ID3V1Header = {0};
            printf("mp3ID3V1Header_t size %d\n", sizeof(mp3ID3V1Header_t));
            fread(&mp3ID3V1Header, 1, sizeof(mp3ID3V1Header_t), file);
            printf("--->> mp3ID3V1Header tag [%s] mp3Name [%s] mp3Author [%s] mp3Album [%s] mp3Year [%#x] mp3style [%d]\n",
                   mp3ID3V1Header.tag,
                   mp3ID3V1Header.mp3Name,
                   mp3ID3V1Header.mp3Author,
                   mp3ID3V1Header.mp3Album,
                   mp3ID3V1Header.mp3Year,
                   mp3ID3V1Header.mp3style);
            break;
        }

        if (mp3DataHeader.existCRC == 0)
        {
            uint16_t CRC = 0;
            fread(&CRC, 1, 2, file);
            printf("crc %d\n", CRC);
        }

        printf("mp3 channel info index %#x\n", ftell(file));
        mp3Sideinfo_t channelInfo = {0};
        // printf("channel info size %d\n", sizeof(mp3Sideinfo_t));
        // fread(&channelInfo, 1, sizeof(mp3Sideinfo_t), file);
        fread(&channelInfo, 1, 32, file);
        // mp3ChannelInfoParse(channelInfo);

        //
        printf("mp3 VBR OR CBR data HEADER index %#x\n", ftell(file));
        mp3VBRHeader_t mp3VBRHeader = {0};
        fread(&mp3VBRHeader, 1, sizeof(mp3VBRHeader_t), file);
        printf(
            "mp3VBRHeader header [%#x]  fileFlag [%d] frameNumber [%d] fileLength [%d]\n",
            mp3VBRHeader.header,
            mp3VBRHeader.fileFlag,
            mp3VBRHeader.frameNumber,
            mp3VBRHeader.fileLength);

        //
        frameLength = (frameLength - 32 - 4 - sizeof(mp3VBRHeader_t));
        printf("mp3 VBR OR CBR data addr index [%#x] data len [%d]\n", ftell(file), frameLength);
        uint8_t *rawData = (uint8_t *)malloc(frameLength);
        if (rawData == NULL)
        {
            isdataParam = false;
            printf("malloc fail!!\n");
            break;
        }
        memset(rawData, 0, frameLength);
        fread(rawData, 1, frameLength, file);

        //////////////////
        // VBR OR CBR 数据 在rawData,需要二次解析自己实现

        /////////////////

        if (rawData != NULL)
        {
            free(rawData);
            rawData = NULL;
        }

    } while (isdataParam);

    printf("parse ok!\n");
    fclose(file);
    return 0;
}

int main(int argc, char *argv[])
{
    printf("param count %d\n", argc);
    for (int i = 0; i < argc; i++)
    {
        printf("param[%d] %s\n", i, argv[i]);
    }

    if (argc < 2)
    {
        printf("This tool is only used to parse mp3 files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.mp3\n");
        return 0;
    }

    if ((strcmp(argv[1], "help") == 0) || (strcmp(argv[1], "-h") == 0))
    {
        printf("This tool is only used to parse mp3 files, and is very basic, for reference only\n");
        printf("Usage is as follows: *.exe *.mp3\n");
        return 0;
    }

    mp3Parse(argv[1]);
    return 0;
}
